package com.egreen.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.egreen.common.pojo.DTO.system.AddCommodityExchangeRecordDTO;
import com.egreen.common.pojo.DTO.system.ReduceStockDTO;
import com.egreen.common.pojo.VO.user.UserDetailVO;
import com.egreen.common.pojo.DTO.asset.OperatePointRecordingDTO;
import com.egreen.common.pojo.entity.system.Commodity;
import com.egreen.common.pojo.entity.user.*;
import com.egreen.common.serviceapi.asset.IAssetServiceApi;
import com.egreen.common.serviceapi.system.ISystemAPI;
import com.egreen.common.serviceapi.system.VerificationCodeAPI;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.egreen.common.pojo.DTO.user.userServiceDTO.*;
import com.egreen.user.exceptions.UserException;
import com.egreen.user.dao.UserDao;
import com.egreen.user.service.*;
import com.egreen.user.utils.UserUtil;
import com.egreen.common.States;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.sql.SQLClientInfoException;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author cloudJiang
 * @since 2022-07-16
 */
@Service
@Lazy
public class UserServiceImpl extends ServiceImpl<UserDao, User> implements IUserService {

    @Autowired
    UserUtil util;

    @Lazy
    @Autowired
    IUserLoginAccountService loginAccountService;

    @Autowired
    IUserLocationService userLocationService;

    @Autowired
    ILocationDetailService locationDetailService;

    @Autowired
    IProvinceService provinceService;

    @Autowired
    IInvitedService iInvitedService;

    @DubboReference
    VerificationCodeAPI verificationCodeAPI;

    @DubboReference
    IAssetServiceApi assetServiceApi;

    @DubboReference
    ISystemAPI systemAPI;


    @Override
    @Transactional(rollbackFor = {SQLClientInfoException.class, UserException.class})
    public Long signUp(SignUpDTO signUpDTO) {
        //查询手机号是否已存在
        QueryWrapper<UserLoginAccount> phonewrapper = new QueryWrapper<>();
        phonewrapper.eq("phone", signUpDTO.getPhone());
        UserLoginAccount userLoginAccount1 = loginAccountService.getOne(phonewrapper);
        if (userLoginAccount1 != null) {
            throw new UserException(States.ERR_SELECT.getStates(), "该电话号码已经被注册，请更换号码");
        }

        /*//验证验证码是否正确
        String verificationCode = verificationCodeAPI.getVerificationCode(signUpDTO.getPhone());
        if (verificationCode == null || !verificationCode.equals(signUpDTO.getValidCode())) {
            throw new UserException(States.ERR_SELECT.getStates(), "验证码不正确，请核对后再输入");
        }
*/
        //判断用户名在表中是否重复
        QueryWrapper<User> usernamewrapper = new QueryWrapper<>();
        usernamewrapper.eq("user_name", signUpDTO.getUserName());
        User users = this.getOne(usernamewrapper);
        if (users != null) {
            throw new UserException(States.ERR_UNIQUE.getStates(), "用户名已经存在");
        }

        //向数据库中添加一条记录
        UserLoginAccount userLoginAccount = new UserLoginAccount();
        userLoginAccount.setPhone(signUpDTO.getPhone());
        userLoginAccount.setPassword(util.encryptByMD5(signUpDTO.getPassword()));
        boolean save = loginAccountService.save(userLoginAccount);
        if (!save) {
            throw new UserException(States.ERR_INSERT.getStates(),
                    "插入user_login_account表数据失败，请检查参数，稍后重试");
        }

        //插入用户表
        User user = new User();
        user.setStates(0);
        user.setUserName(signUpDTO.getUserName());
        user.setLoginAccountId(userLoginAccount.getId());
        user.setPointAccountId(assetServiceApi.addPointAccount());
        user.setBalanceAccountId(assetServiceApi.addBalanceAccount());
        this.save(user);
        user.setInvitationCode(UserUtil.invitationCodeGenerating(user.getId()));
        this.updateById(user);


        //判断用户是否填写了正确的邀请码，如果填写则为邀请者增加邀请人数和资产（积分等）
        if (!(signUpDTO.getInvitationCode() == null) && !signUpDTO.getInvitationCode().equals("")) {
            QueryWrapper<User> inviterWrapper = new QueryWrapper<>();
            inviterWrapper.eq("invitation_code", signUpDTO.getInvitationCode());
            User inviter = this.getOne(inviterWrapper);

            if (inviter == null) {
                throw new UserException(States.ERR_UNIQUE.getStates(), "邀请码不存在");
            } else {
                inviter.setInvitedNumber(inviter.getInvitedNumber() + 1);
                this.updateById(inviter);

                //增加一条邀请记录
                Invited invited = new Invited();
                invited.setInviteUserId(inviter.getId());
                invited.setInvitedUserId(user.getId());
                iInvitedService.save(invited);

                //为邀请者增加积分
                int num = 5;
                OperatePointRecordingDTO operatePointRecordingDTO = new OperatePointRecordingDTO();
                operatePointRecordingDTO.setId(inviter.getId());
                operatePointRecordingDTO.setPointAccountId(inviter.getPointAccountId());
                operatePointRecordingDTO.setOperate("增加");
                operatePointRecordingDTO.setOperatePointNum(num);
                assetServiceApi.updateByPoint(operatePointRecordingDTO);
            }
        }

        return user.getId();
    }


    @Override
    //@Transactional(rollbackFor = {SQLClientInfoException.class, UserException.class})
    public void completeInformation(CompleteInformationDTO completeInformationDTO) {
        //将用户提交的邮箱地址更新到数据库
        UserLoginAccount userLoginAccount = new UserLoginAccount();
        userLoginAccount.setId(this.getById(completeInformationDTO.getUserID()).getLoginAccountId());
        if (completeInformationDTO.getEmail() != null) {
            userLoginAccount.setEmail(completeInformationDTO.getEmail());
            loginAccountService.updateById(userLoginAccount);
        }

        //将用户提交的详细地址信息保存到数据库
        LocationDetail locationDetail = new LocationDetail();
        BeanUtils.copyProperties(completeInformationDTO, locationDetail);
        locationDetailService.save(locationDetail);

        //将用户的地址信息保存到数据库
        UserLocation userLocation = new UserLocation();
        userLocation.setCountryId(1);
        QueryWrapper<Province> wrapper = new QueryWrapper();
        wrapper.eq("name", completeInformationDTO.getProvince());
        userLocation.setProvinceId(provinceService.getOne(wrapper).getId());
        userLocation.setCityName(completeInformationDTO.getCity());
        userLocation.setDetailId(locationDetail.getId());
        userLocationService.save(userLocation);

        //将用户的地址ID保存到数据库
        User user = new User();
        user.setId(completeInformationDTO.getUserID());
        user.setLocationId(userLocation.getId());
        this.updateById(user);
    }


    @Override
    @Transactional(rollbackFor = {SQLClientInfoException.class, UserException.class})
    public void sendVerificationCode(SendVerificationCodeDTO sendVerificationCodeDTO) {
        //判断发送对象是手机号还是邮箱。如果是已注册用户，以id+验证码的形式存储验证码，如果是尚未注册的用户则以手机或邮箱+验证码的形式存储
        if (util.isNumeric(sendVerificationCodeDTO.getSendTo()) && sendVerificationCodeDTO.getSendTo().length() == 11) {
            QueryWrapper<UserLoginAccount> wrapper = new QueryWrapper();
            wrapper.eq("phone", sendVerificationCodeDTO.getSendTo());
            UserLoginAccount loginAccount = loginAccountService.getOne(wrapper);
            if (loginAccount == null) {
                verificationCodeAPI.addVerificationCode(sendVerificationCodeDTO.getSendTo(), util.sendValidSms(sendVerificationCodeDTO.getSendTo()));
            } else {
                QueryWrapper<User> userWrapper = new QueryWrapper();
                userWrapper.eq("login_account_id", loginAccount.getId());
                User user = this.getOne(userWrapper);
                verificationCodeAPI.addVerificationCode(user.getId(), util.sendValidSms(sendVerificationCodeDTO.getSendTo()));
            }

        } else if (util.isEmail(sendVerificationCodeDTO.getSendTo())) {
            QueryWrapper<UserLoginAccount> wrapper = new QueryWrapper();
            wrapper.eq("email", sendVerificationCodeDTO.getSendTo());
            UserLoginAccount loginAccount = loginAccountService.getOne(wrapper);
            if (loginAccount == null) {
                verificationCodeAPI.addVerificationCode(sendVerificationCodeDTO.getSendTo(), util.sendValidEmail(sendVerificationCodeDTO.getSendTo()));
            } else {
                QueryWrapper<User> userWrapper = new QueryWrapper();
                userWrapper.eq("login_account_id", loginAccount.getId());
                User user = this.getOne(userWrapper);
                verificationCodeAPI.addVerificationCode(user.getId(), util.sendValidEmail(sendVerificationCodeDTO.getSendTo()));
            }
        }
    }


    @Override
    @Transactional(rollbackFor = {SQLClientInfoException.class, UserException.class})
    public void changeIcon(ChangeIconDTO changeIconDTO) {
        User user = new User();
        user.setId(changeIconDTO.getUserID());
        user.setIconUrl(changeIconDTO.getIconURL());
        this.updateById(user);
    }

    @Override
    @Transactional(rollbackFor = {SQLClientInfoException.class, UserException.class})
    public Boolean comparisonValidCode(String sendTo, String validCode) {
        //判断发送对象是手机号还是邮箱。如果是已注册用户，以id+验证码的形式存储验证码，如果是尚未注册的用户则以手机或邮箱+验证码的形式存储
        if (util.isNumeric(sendTo) && sendTo.length() == 11) {
            QueryWrapper<UserLoginAccount> wrapper = new QueryWrapper();
            wrapper.eq("phone", sendTo);
            UserLoginAccount loginAccount = loginAccountService.getOne(wrapper);
            if (loginAccount == null) {
                return validCode.equals(verificationCodeAPI.getVerificationCode(sendTo));
            } else {
                QueryWrapper<User> userWrapper = new QueryWrapper();
                userWrapper.eq("login_account_id", loginAccount.getId());
                User user = this.getOne(userWrapper);
                return validCode.equals(verificationCodeAPI.getVerificationCode(user.getId()));
            }
        } else if (util.isEmail(sendTo)) {
            QueryWrapper<UserLoginAccount> wrapper = new QueryWrapper();
            wrapper.eq("email", sendTo);
            UserLoginAccount loginAccount = loginAccountService.getOne(wrapper);
            if (loginAccount == null) {
                return validCode.equals(verificationCodeAPI.getVerificationCode(sendTo));
            } else {
                QueryWrapper<User> userWrapper = new QueryWrapper();
                userWrapper.eq("login_account_id", loginAccount.getId());
                User user = this.getOne(userWrapper);
                return validCode.equals(verificationCodeAPI.getVerificationCode(user.getId()));
            }
        } else {
            return false;
        }
    }

    @Override
    public UserDetailVO getUserMessage(Long userId) {
        if (userId == null) {
            throw new UserException(States.ERR_USER_NOT_FOUND.getStates(), "用户id不能为空");
        }

        UserDetailVO detailVO = new UserDetailVO();
        User u = this.getById(userId);
        if (u == null) {
            throw new UserException(States.ERR_USER_NOT_FOUND.getStates(), States.ERR_USER_NOT_FOUND.getDescription());
        }

        //查询用户手机号以及邮箱
        Long loginAccountId = u.getLoginAccountId();
        String email = loginAccountService.getEmail(loginAccountId);
        String turePhone = loginAccountService.getTurePhone(loginAccountId);

        //查询账户余额
        //查询账户积分余额
        Long pointAccountId = u.getPointAccountId();
        Long balanceAccountId = u.getBalanceAccountId();
        BigDecimal balance = assetServiceApi.selectBalanceByAccountId(balanceAccountId);
        Integer point = assetServiceApi.selectPointByAccountId(pointAccountId);

        //查询出用户地址
        Long locationId = u.getLocationId();
        UserLocation userLocation = userLocationService.getById(locationId);
        LocationDetail locationDetail = locationDetailService.getById(userLocation.getDetailId());
        String proName = provinceService.getById(userLocation.getProvinceId()).getName();


        //组织vo
        detailVO.setName(u.getUserName());
        detailVO.setIconUrl(u.getIconUrl() == null ? "/imgs/userIcon/defult.jpg" : u.getIconUrl());
        detailVO.setEmail(email == null ?
                "暂未绑定邮箱" : email);
        detailVO.setPhone(turePhone);
        detailVO.setPoint(point);
        detailVO.setLocation(proName + userLocation.getCityName() + locationDetail.getDistrict() +
                locationDetail.getCommunity() + locationDetail.getLocationDetails());
        detailVO.setBalance(balance);
        // 支付宝信息待添加

        return detailVO;
    }

    @Override
    @Transactional(rollbackFor = {SQLClientInfoException.class, UserException.class})
    public void commodityExchange(CommodityExchangeDTO commodityExchangeDTO) {
        /*查询用户积分余额*/
        User user = this.getById(commodityExchangeDTO.getUserId());
        Integer point = assetServiceApi.selectPointByAccountId(user.getPointAccountId());
        /*查询商品所需积分*/
        Commodity commodity = systemAPI.selectCommodity(commodityExchangeDTO.getCommodityId());

        //扣除用户积分
        OperatePointRecordingDTO operatePointRecordingDTO = new OperatePointRecordingDTO();
        operatePointRecordingDTO.setId(commodityExchangeDTO.getUserId());
        operatePointRecordingDTO.setPointAccountId(user.getPointAccountId());
        operatePointRecordingDTO.setOperate("积分兑换商品");
        operatePointRecordingDTO.setOperatePointNum(commodity.getPrice().intValue());
        assetServiceApi.updateByPoint(operatePointRecordingDTO);

        //减少商品库存
        ReduceStockDTO reduceStockDTO = new ReduceStockDTO();
        reduceStockDTO.setId(commodityExchangeDTO.getCommodityId());
        reduceStockDTO.setRemainingQuantity(commodity.getRemainingQuantity() - 1);
        systemAPI.reduceStock(reduceStockDTO);

        //添加一条兑换记录
        AddCommodityExchangeRecordDTO addCommodityExchangeRecordDTO = new AddCommodityExchangeRecordDTO();
        addCommodityExchangeRecordDTO.setUserId(commodityExchangeDTO.getUserId());
        addCommodityExchangeRecordDTO.setCommodityId(commodityExchangeDTO.getCommodityId());
        addCommodityExchangeRecordDTO.setState("1");
        addCommodityExchangeRecordDTO.setLogisticsInformation("未发货");
        systemAPI.addCommodityExchangeRecord(addCommodityExchangeRecordDTO);
    }


    @Override
    public String getInvitationCode(Long userId) {
        return this.getById(userId).getInvitationCode();
    }
}
